
module Api
  module V1

    class ApplicationController < Lina::ApplicationController

      #include Concerns::AuthTokenConcern

      attr_accessor :current_user

      # disable the CSRF token
      protect_from_forgery with: :null_session

      # disable cookies (no set-cookies header in response)
      before_action :set_cache_control_headers

      before_action :simple_ua_validate

      # disable the CSRF token
      skip_before_action :verify_authenticity_token

      class ParameterValueNotAllowed < ActionController::ParameterMissing
        attr_reader :values
        def initialize(param, values) # :nodoc:
          @param = param
          @values = values
          super("param: #{param} value not allowed: #{values}")
        end
      end

      class AccessDenied < StandardError; end
      class PageNotFound < StandardError; end

      class ParameterValueNotCorrect < StandardError
        def initialize(msg="")
          super(msg)
        end
      end

      rescue_from(ParameterValueNotCorrect) do |err|
        render json: { error: 'ParameterInvalid', message: err.message }, status: 400
      end

      rescue_from(ActionController::ParameterMissing) do |err|
        render json: { error: 'ParameterInvalid', message: err }, status: 400
      end

      rescue_from(ActiveRecord::RecordInvalid) do |err|
        render json: { error: 'RecordInvalid', message: err }, status: 400
      end

      rescue_from(AccessDenied) do |err|
        render json: { error: 'Forbidden', message: "没有访问权限" }, status: 403
      end

      rescue_from(JWT::ExpiredSignature) do |err|
        render json: { error: 'Unauthorized', message: "权限验证失败" }, status: 401
      end

      rescue_from(JWT::DecodeError) do |err|
        render json: { error: 'Unauthorized', message: "权限验证失败" }, status: 401
      end

      rescue_from(ActiveRecord::RecordNotFound) do
        render json: { error: 'ResourceNotFound' }, status: 404
      end

      #rescue_from Lina::ParamsCheckError do |exception|
        #render json: { error: 'ParameterInvalid', message: exception}, status: 400
      #end
      #
      def requires!(name, opts = {})
        opts[:require] = true
        optional!(name, opts)
      end

      def optional!(name, opts = {})
        if params[name].blank? && opts[:require] == true
          raise ActionController::ParameterMissing.new(name)
        end

        if opts[:values] && params[name].present?
          values = opts[:values].to_a
          if !values.include?(params[name]) && !values.include?(params[name].to_i)
            raise ParameterValueNotAllowed.new(name, opts[:values])
          end
        end

        if params[name].blank? && opts[:default].present?
          params[name] = opts[:default]
        end
      end

      def params_validate!(name, custom_error=nil)
        params_entry = params[name]
        unless (yield(params_entry))
          if custom_error
            raise custom_error
          else
            raise ParameterValueNotAllowed.new(name, params_entry)
          end
        end
      end

      def authenticated!
        set_authenticated{|| return unauthenticated!}
      end

      def set_authenticated
        jwt, options = ActionController::HttpAuthentication::Token.token_and_options(request)

        return if jwt.nil? && !block_given?
        payload, header = JWT.decode(jwt, nil, false, verify_expiration: true)
        mobile = options.blank? ? nil : options[:mobile]
        user = mobile && User.find_by(mobile: mobile)

        if user
          #验证password_digest，防止用户修改密码后扔能使用老的token
          secret = user ? user.password_digest : ""
          JWT.decode(jwt, secret)
          self.current_user = user
        else
          if block_given?
            yield
          end
        end

      end

      def unauthenticated!
        api_error(erorr: 'Unauthorized', message: "权限验证失败", status: 401)
      end

      def api_error(opts = {})
        render json: {error:  opts[:error] || '', message: opts[:message] || ''}, status: opts[:status]
      end

      def render_success_for_api(msg=nil, others={})
        render :json => {
          error_code: 0,
          data: {
            message: msg.to_s
          }.merge!(others)
        }
      end

      def render_fail_for_api(opts={})
        res = {
          error_code: opts[:error_code] || 1,
          data: { message: opts[:msg] || '' }
        }

        model = opts[:model]
        if model
          if model.kind_of?(Hash)
            res[:data].merge!(model)
          else
            res[:data].merge!( errors: flatten_errors(model.errors.messages) )
          end
        end

        render :json => res, status: opts[:status] || :ok
      end


      private

      def set_cache_control_headers
        request.session_options[:skip] = true
        response.headers['Cache-Control'] = 'public, no-cache'
      end

      def simple_ua_validate
        authenticate_or_request_with_http_token do |token, options|
          token =~ /#{Rails.configuration.x.authed_api_user_agent}/
        end
        #return unauthenticated! unless request.user_agent =~ /#{Rails.configuration.x.authed_api_user_agent}/
      end

    end

  end
end
